package de.mmis.core.publishsubscribe;

import de.mmis.core.base.event.Event;
import de.mmis.core.base.event.Observable;
import de.mmis.core.base.event.Observer;
import de.mmis.core.publishsubscribe.filter.Filter;

/**
 * The main interface of the Publish/Subscribe system.
 * 
 * @author Martin Nyolt
 * 
 */
public interface PublishSubscribe {

	public static class PublishSubscribeException extends Exception {

		private static final long serialVersionUID = -8594565835617372048L;

		public PublishSubscribeException() {
			super();
		}

		public PublishSubscribeException(String message) {
			super(message);
		}

		public PublishSubscribeException(Throwable cause) {
			super(cause);
		}

		public PublishSubscribeException(String message, Throwable cause) {
			super(message, cause);
		}
	}

	/**
	 * Makes the Publish/Subscribe system listen for {@link Event}s of the
	 * producer. These Events will distributed to all consumers who are
	 * registered as an {@link Observer}.
	 * 
	 * @param producer
	 *            The {@link Observable} which generates the Events
	 * @param id
	 *            The id of the producer
	 * 
	 * @see #removeObservable(Observable) removeObservable
	 * @see #subscribe(Class, Filter, Observer) subscribe
	 */
	public <T extends Event> void addObservable(Observable<T> producer,
			String id) throws PublishSubscribeException;

	/**
	 * Removed a previously registered {@link Observable}, such that the
	 * Publish/Subscribe system will no longer listen for {@link Event}s.
	 * 
	 * @param producer
	 * @throws PublishSubscribeException
	 * 
	 * @see #addObservable(Observable, String) addObservable
	 */
	public <T extends Event> void removeObservable(Observable<T> producer)
			throws PublishSubscribeException;

	/**
	 * Registers the {@link Observer}, so it will receive {@link Event}s of the
	 * specified class which match the filter. An additional Observer of
	 * {@link PlainEvent}s can be specified, to receive all event data and
	 * meta-data.
	 * 
	 * @param <T>
	 *            the type of the Event
	 * @param clazz
	 *            The {@link Class}-Object of T
	 * @param filter
	 *            The {@link Filter} each Event must match.
	 * @param consumer
	 *            the Observer to notify of new Events
	 * 
	 * @return an ID to unsubscribe
	 * 
	 * @see #unsubscribe(Integer) unsubscribe
	 */
	// * @see #unsubscribeAll(Observer) unsubscribeAll
	public <T extends Event> Integer subscribe(Class<T> clazz, Filter filter,
			Observer<? super T> consumer, Observer<PlainEvent> plainConsumer)
			throws PublishSubscribeException;

	/**
	 * Registers the {@link Observer}, so it will receive {@link Event}s of the
	 * specified class which match the filter.
	 * 
	 * @param <T>
	 *            the type of the Event
	 * @param clazz
	 *            The {@link Class}-Object of T
	 * @param filter
	 *            The {@link Filter} each Event must match.
	 * @param consumer
	 *            the Observer to notify of new Events
	 * 
	 * @return an ID to unsubscribe
	 * 
	 * @see #unsubscribe(Integer) unsubscribe
	 */
	// @see #unsubscribeAll(Observer) unsubscribeAll
	public <T extends Event> Integer subscribe(Class<T> clazz, Filter filter,
			Observer<? super T> consumer) throws PublishSubscribeException;

	/**
	 * Unregisters the {@link Observer} that was registered by a call to
	 * {@link #subscribe(Class, Filter, Observer) subscribe}. If the same
	 * Observer was registered more than once, it will still get the Events of
	 * the other subscribtions.
	 * 
	 * @param id
	 * 
	 * @see #subscribe(Class, Filter, Observer) subscribe
	 */
	// @see #unsubscribeAll(Observer) unsubscribeAll
	public void unsubscribe(Integer id);

	/**
	 * Unregisters the {@link Observer} of all subscriptions.
	 * 
	 * @param consumer
	 * 
	 * @see #subscribe(Class, Filter, Observer) subscribe
	 * @see #unsubscribe(Integer) unsubscribe
	 */
	// public void unsubscribeAll(Observer<?> consumer);
}
